#include <ecal/ecal.h>
#include <ecal/msg/protobuf/subscriber.h>

#include <atomic>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <map>
#include <mutex>
#include <thread>

#include "protocol/hello_world.pb.h"

class PacketLossMonitor {
 public:
  void processMessage(const std::string& sender, uint32_t id) {
    std::lock_guard<std::mutex> lock(mutex_);

    // 获取或创建发送者的状态
    SenderState& state = senders_[sender];

    // 如果是第一条消息
    if (state.expected_id == 0) {
      state.expected_id = id + 1;
      state.total_received++;
      return;
    }

    // 检查消息ID连续性
    if (id != state.expected_id) {
      // 计算丢失的消息数量（考虑ID回绕）
      uint32_t lost_count =
          (id > state.expected_id) ? (id - state.expected_id) : (UINT32_MAX - state.expected_id + id + 1);

      state.total_lost += lost_count;
      state.last_loss = std::chrono::steady_clock::now();

      // 限流丢包日志输出
      auto now = std::chrono::steady_clock::now();
      if (now - state.last_report > std::chrono::seconds(1)) {
        std::cout << "[WARNING] Packet loss detected from " << sender << ": expected " << state.expected_id
                  << ", received " << id << " (" << lost_count << " packets lost)" << std::endl;
        state.last_report = now;
      }
    }

    // 更新期望ID（处理回绕）
    state.expected_id = (id == UINT32_MAX) ? 0 : id + 1;
    state.total_received++;
  }

  void printStats() const {
    std::lock_guard<std::mutex> lock(mutex_);

    if (senders_.empty()) {
      std::cout << "No messages received yet." << std::endl;
      return;
    }

    auto now = std::chrono::steady_clock::now();

    std::cout << "\n===== Packet Loss Statistics =====" << std::endl;
    for (const auto& [sender, state] : senders_) {
      uint64_t total = state.total_received + state.total_lost;
      double loss_rate = (total > 0) ? (static_cast<double>(state.total_lost) / total * 100.0) : 0.0;

      std::cout << "Sender: " << sender << "\n"
                << "  Received: " << state.total_received << "\n"
                << "  Lost: " << state.total_lost << "\n"
                << "  Loss rate: " << std::fixed << std::setprecision(2) << loss_rate << "%\n"
                << "  Last loss: "
                << (state.total_lost > 0
                        ? std::chrono::duration_cast<std::chrono::seconds>(now - state.last_loss).count()
                        : -1)
                << " seconds ago\n"
                << "  Current expected ID: " << state.expected_id << "\n"
                << "----------------------------------" << std::endl;
    }
    std::cout << "==================================\n" << std::endl;
  }

  void periodicReport(int interval_sec) {
    while (!stop_reporting_) {
      printStats();
      std::this_thread::sleep_for(std::chrono::seconds(interval_sec));
    }
  }

  void stopReporting() { stop_reporting_ = true; }

 private:
  struct SenderState {
    uint32_t expected_id = 0;                           // 期望的下一个ID
    uint64_t total_received = 0;                        // 接收到的消息总数
    uint64_t total_lost = 0;                            // 丢失的消息总数
    std::chrono::steady_clock::time_point last_loss;    // 最后一次丢包时间
    std::chrono::steady_clock::time_point last_report;  // 最后一次报告时间
  };

  mutable std::mutex mutex_;
  std::map<std::string, SenderState> senders_;
  std::atomic<bool> stop_reporting_{false};
};

int main(int argc, char** argv) {
  // 初始化eCAL和创建protobuf订阅者
  eCAL::Initialize(argc, argv, "Hello World Protobuf Subscriber");
  eCAL::protobuf::CSubscriber<example::HelloWorld> subscriber("hello_world_protobuf");

  // 创建丢包监控器
  PacketLossMonitor monitor;

  // 设置回调 - 使用lambda捕获监控器
  subscriber.AddReceiveCallback([&monitor](const char* /* topic_name */, const example::HelloWorld& msg,
                                           long long /* time */, long long /* clock */, long long /* id */) {
    std::cout << msg.name() << " sent a message with ID " << msg.id() << ":" << std::endl
              << msg.msg() << std::endl
              << std::endl;

    // 处理消息进行丢包检测
    monitor.processMessage(msg.name(), msg.id());
  });

  // 启动定期报告线程
  int report_interval = 10;  // 每10秒报告一次
  std::thread report_thread(&PacketLossMonitor::periodicReport, &monitor, report_interval);

  std::cout << "Subscriber running. Press Enter to exit..." << std::endl;

  // 主循环 - 等待退出
  while (eCAL::Ok()) {
    // 更高效的休眠方式
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // 检查是否有键盘输入（非阻塞）
    if (std::cin.rdbuf()->in_avail() > 0) {
      break;
    }
  }

  // 停止报告线程并打印最终统计
  monitor.stopReporting();
  if (report_thread.joinable()) {
    report_thread.join();
  }

  std::cout << "\nFinal packet loss statistics:" << std::endl;
  monitor.printStats();

  // 终止eCAL
  eCAL::Finalize();
  return 0;
}